/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.diplomka.datalayer.daoimpl;

import cz.fi.muni.diplomka.common.enumeration.ResourceType;
import cz.muni.fi.diplomka.datalayer.dao.CityResourcesDao;
import cz.muni.fi.diplomka.datalayer.entity.CityResourcesEntity;
import cz.muni.fi.diplomka.datalayer.util.DbConnector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;

/**
 *
 * @author Jakub Kutil
 */
public class CityResourcesDaoImpl implements CityResourcesDao {

    @Override
    public void addResourcesInCity(CityResourcesEntity resourcesInCityEntity) {
        if (resourcesInCityEntity == null) {
            throw new IllegalArgumentException("Resources In City Entity can not be null.");
        }

        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();

        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("cityId", resourcesInCityEntity.getCityId());
            params.put("resource", resourcesInCityEntity.getResource().toString());
            params.put("resourceCount", resourcesInCityEntity.getResourceCount());

            String query = "MATCH (City:City {id : {cityId}})"
                    + "CREATE (ResourcesInCity: ResourcesInCity {resource : {resource}, resourceCount : {resourceCount}})"
                    + "<-[r:STORED]-(City)";
            engine.execute(query, params);
            t.success();
        }
    }

    @Override
    public void editResourcesInCity(CityResourcesEntity resourcesInCityEntity) {
        if (resourcesInCityEntity == null) {
            throw new IllegalArgumentException("Resources In City Entity can not be null.");
        }

        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();

        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("cityId", resourcesInCityEntity.getCityId());
            params.put("resource", resourcesInCityEntity.getResource().toString());
            params.put("resourceCount", resourcesInCityEntity.getResourceCount());

            String query = "MATCH (City:City { id :{cityId}})-[r:STORED]->(ResourcesInCity:ResourcesInCity { resource : {resource}})"
                    + "SET ResourcesInCity.resourceCount = {resourceCount}";
            engine.execute(query, params);
            t.success();
        }
    }

    @Override
    public List<CityResourcesEntity> getAllResourcesInCityOfPlayer(Long cityId) {
        if (cityId == null) {
            throw new IllegalArgumentException("City Id can not be null.");
        }

        List<CityResourcesEntity> cityResourcesList = new ArrayList<>();
        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();


        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("cityId", cityId);

            String query = "MATCH (City:City { id :{cityId}})-[r:STORED]->(ResourcesInCity:ResourcesInCity)"
                    + "RETURN ResourcesInCity";
            ExecutionResult result = engine.execute(query, params);
            Iterator<Node> resources = result.columnAs("ResourcesInCity");
            while (resources.hasNext()) {
                Node node = resources.next();
                CityResourcesEntity cityResourcesEntity = new CityResourcesEntity();
                cityResourcesEntity.setCityId(cityId);
                cityResourcesEntity.setResource(ResourceType.valueOf(node.getProperty("resource").toString()));
                cityResourcesEntity.setResourceCount(Integer.valueOf(node.getProperty("resourceCount").toString()));

                cityResourcesList.add(cityResourcesEntity);
            }
            t.success();
        }
        return cityResourcesList;
    }

    @Override
    public int getAllSpecificResourcesCountInCityOfPlayer(Long cityId, ResourceType resourceType) {
        if (cityId == null) {
            throw new IllegalArgumentException("City Id can not be null.");
        }

        if (resourceType == null) {
            throw new IllegalArgumentException("Resource Type can not be null.");
        }

        CityResourcesEntity cityResourcesEntity = new CityResourcesEntity();

        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();


        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("cityId", cityId);
            params.put("resource", resourceType.toString());

            String query = "MATCH (City:City { id :{cityId}})-[r:STORED]->(ResourcesInCity:ResourcesInCity { resource : {resource}})"
                    + "RETURN ResourcesInCity";
            ExecutionResult result = engine.execute(query, params);
            Iterator<Node> resources = result.columnAs("ResourcesInCity");
            while (resources.hasNext()) {
                Node node = resources.next();

                cityResourcesEntity.setCityId(cityId);
                cityResourcesEntity.setResource(ResourceType.valueOf(node.getProperty("resource").toString()));
                cityResourcesEntity.setResourceCount(Integer.valueOf(node.getProperty("resourceCount").toString()));

            }
            t.success();
        }
        return cityResourcesEntity.getResourceCount();
    }
}
